﻿// -------------------------------------------------------------------------
//    @FileName         :    EdgeCaseTest.cpp
//    @Author           :    gaoyi
//    @Date             :    2025/1/20
//    @Email            :    445267987@qq.com
//    @Module           :    EdgeCaseTest
//
// -------------------------------------------------------------------------

#include "BagSystemTestBase.h"
#include "MockItemDesc.h"

/**
 * @brief 边界条件和异常处理测试类
 * 
 * 测试背包系统的边界条件和异常处理：
 * - 空指针和无效参数处理
 * - 背包容量边界测试
 * - 物品数量溢出测试
 * - 并发操作安全性测试
 * - 内存和资源限制测试
 */
class EdgeCaseTest : public BagSystemTestBase {
protected:
    void SetUp() override {
        BagSystemTestBase::SetUp();
        m_testPlayer = CreateTestPlayer();
    }
    
    void TearDown() override {
        m_testPlayer = nullptr;
        BagSystemTestBase::TearDown();
    }

protected:
    NFPlayer* m_testPlayer;
};

// === 空指针和无效参数测试 ===

/**
 * @brief 测试空指针参数处理
 */
TEST_F(EdgeCaseTest, NullPointerParametersTest) {
    // 测试NFServicePackage的空指针处理
    ASSERT_NE(NFServicePackage::AddByItemIDAndNum(nullptr, TEST_REASON_SYSTEM, TestItemIds::NORMAL_ITEM_1, 1), 0)
        << "空玩家指针应该返回错误";
    
    ASSERT_EQ(NFServicePackage::GetBagPage(nullptr, TEST_BAG_TYPE_NORMAL), nullptr)
        << "空玩家指针获取背包应该返回nullptr";
    
    ASSERT_EQ(NFServicePackage::GetMoney(nullptr, TEST_MONEY_TYPE_GOLD), nullptr)
        << "空玩家指针获取金钱应该返回nullptr";
    
    ASSERT_EQ(NFServicePackage::GetMoneyNumber(nullptr, TEST_MONEY_TYPE_GOLD), 0)
        << "空玩家指针获取金钱数量应该返回0";
    
    // 测试空输出参数处理
    int result = NFServicePackage::AddByItemIDAndNum(m_testPlayer, TEST_REASON_SYSTEM, TestItemIds::NORMAL_ITEM_1, 1);
    ASSERT_EQ(result, 0) << "正常添加物品应该成功";
    
    // 测试空容器参数
    std::vector<Item> emptyItems;
    int emptyResult = NFServicePackage::AddItems(m_testPlayer, emptyItems, TEST_REASON_SYSTEM);
    ASSERT_EQ(emptyResult, 0) << "添加空物品列表应该成功";
}

/**
 * @brief 测试无效参数处理
 */
TEST_F(EdgeCaseTest, InvalidParametersTest) {
    // 测试无效物品ID
    ASSERT_NE(NFServicePackage::AddByItemIDAndNum(m_testPlayer, TEST_REASON_SYSTEM, -1, 1), 0)
        << "负数物品ID应该返回错误";
    
    ASSERT_NE(NFServicePackage::AddByItemIDAndNum(m_testPlayer, TEST_REASON_SYSTEM, 0, 1), 0)
        << "零物品ID应该返回错误";
    
    ASSERT_NE(NFServicePackage::AddByItemIDAndNum(m_testPlayer, TEST_REASON_SYSTEM, 999999, 1), 0)
        << "不存在的物品ID应该返回错误";
    
    // 测试无效数量
    ASSERT_NE(NFServicePackage::AddByItemIDAndNum(m_testPlayer, TEST_REASON_SYSTEM, TestItemIds::NORMAL_ITEM_1, 0), 0)
        << "零数量应该返回错误";
    
    ASSERT_NE(NFServicePackage::AddByItemIDAndNum(m_testPlayer, TEST_REASON_SYSTEM, TestItemIds::NORMAL_ITEM_1, -1), 0)
        << "负数量应该返回错误";
    
    // 测试无效背包类型
    ASSERT_EQ(NFServicePackage::GetBagPage(m_testPlayer, -1), nullptr)
        << "负数背包类型应该返回nullptr";
    
    ASSERT_EQ(NFServicePackage::GetBagPage(m_testPlayer, 999), nullptr)
        << "不存在的背包类型应该返回nullptr";
    
    // 测试无效金钱类型
    ASSERT_EQ(NFServicePackage::GetMoneyNumber(m_testPlayer, -1), 0)
        << "负数金钱类型应该返回0";
    
    ASSERT_EQ(NFServicePackage::GetMoneyNumber(m_testPlayer, 999), 0)
        << "不存在的金钱类型应该返回0";
}

// === 背包容量边界测试 ===

/**
 * @brief 测试背包满容量处理
 */
TEST_F(EdgeCaseTest, BagFullCapacityTest) {
    // 创建小容量背包进行测试
    NFBagPage* smallBag = CreateTestBagPage(TEST_BAG_TYPE_NORMAL, 2);
    
    // 填满背包
    for (int i = 0; i < 2; ++i) {
        NFGridItem item = CreateTestItem(TestItemIds::NORMAL_ITEM_1 + i, 1);
        int result = smallBag->AddItem(item);
        ASSERT_EQ(result, 0) << "向未满背包添加物品应该成功";
    }
    
    // 验证背包已满
    ASSERT_TRUE(smallBag->IsFull()) << "背包应该已满";
    ASSERT_FALSE(smallBag->IsEmpty()) << "满背包不应该为空";
    
    // 尝试向满背包添加物品
    NFGridItem extraItem = CreateTestItem(TestItemIds::NORMAL_ITEM_3, 1);
    int result = smallBag->AddItem(extraItem);
    ASSERT_NE(result, 0) << "向满背包添加物品应该失败";
    
    // 验证背包状态没有改变
    ASSERT_BAG_USED_COUNT(smallBag, 2);
    ASSERT_BAG_EMPTY_COUNT(smallBag, 0);
}

/**
 * @brief 测试背包零容量处理
 */
TEST_F(EdgeCaseTest, ZeroCapacityBagTest) {
    // 创建零容量背包
    NFBagPage* zeroBag = CreateTestBagPage(TEST_BAG_TYPE_NORMAL, 0);
    
    // 验证零容量背包状态
    ASSERT_EQ(zeroBag->GetMaxGrid(), 0) << "零容量背包最大格子应该为0";
    ASSERT_TRUE(zeroBag->IsEmpty()) << "零容量背包应该为空";
    ASSERT_TRUE(zeroBag->IsFull()) << "零容量背包应该被认为是满的";
    
    // 尝试向零容量背包添加物品
    NFGridItem item = CreateTestItem(TestItemIds::NORMAL_ITEM_1, 1);
    int result = zeroBag->AddItem(item);
    ASSERT_NE(result, 0) << "向零容量背包添加物品应该失败";
}

// === 物品数量边界测试 ===

/**
 * @brief 测试最大堆叠数量
 */
TEST_F(EdgeCaseTest, MaxStackCountTest) {
    // 测试超过最大堆叠数的物品
    WillAddItemData willAdd;
    willAdd.itemId = TestItemIds::STACKABLE_ARROW;
    willAdd.count = 1;
    willAdd.quality = TestQuality::WHITE;
    willAdd.bind = false;
    
    NFBagPageOpMgr* opMgr = CreateTestBagOpMgr(m_testPlayer, TEST_REASON_SYSTEM, true);
    
    // 添加大量可堆叠物品（超过通常的最大堆叠数）
    int addedCount = 0;
    int result = opMgr->AddToBag(willAdd, 10000, &addedCount);
    
    // 应该能添加一些，但可能不是全部（取决于最大堆叠限制）
    ASSERT_EQ(result, 0) << "添加大量堆叠物品失败";
    ASSERT_GT(addedCount, 0) << "应该至少添加一些物品";
    
    opMgr->Commit();
    
    // 验证实际添加的数量
    int totalCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::STACKABLE_ARROW, totalCount);
    ASSERT_EQ(totalCount, addedCount) << "实际添加数量与预期不符";
}

/**
 * @brief 测试整数溢出边界
 */
TEST_F(EdgeCaseTest, IntegerOverflowTest) {
    // 测试接近整数边界的物品数量
    const int maxInt = std::numeric_limits<int>::max();
    const int minInt = std::numeric_limits<int>::min();
    
    // 测试最大整数值
    WillAddItemData willAdd;
    willAdd.itemId = TestItemIds::STACKABLE_ARROW;
    willAdd.count = 1;
    willAdd.quality = TestQuality::WHITE;
    willAdd.bind = false;
    
    NFBagPageOpMgr* opMgr = CreateTestBagOpMgr(m_testPlayer, TEST_REASON_SYSTEM, true);
    
    // 尝试添加最大数量的物品
    int addedCount = 0;
    int result = opMgr->AddToBag(willAdd, maxInt, &addedCount);
    
    // 系统应该能处理这种情况，不应该崩溃
    // 具体结果取决于实现，但至少不应该导致程序异常
    ASSERT_TRUE(result == 0 || result != 0) << "处理最大整数应该有明确结果";
    
    // 测试最小整数值（负数）
    int negativeResult = opMgr->AddToBag(willAdd, minInt, &addedCount);
    ASSERT_NE(negativeResult, 0) << "负数数量应该返回错误";
}

// === 并发操作测试 ===

/**
 * @brief 测试同时操作多个背包操作管理器
 */
TEST_F(EdgeCaseTest, ConcurrentOperationsTest) {
    // 创建多个背包操作管理器
    NFBagPageOpMgr* opMgr1 = CreateTestBagOpMgr(m_testPlayer, TEST_REASON_SYSTEM, true);
    NFBagPageOpMgr* opMgr2 = CreateTestBagOpMgr(m_testPlayer, TEST_REASON_QUEST, true);
    
    WillAddItemData willAdd1, willAdd2;
    willAdd1.itemId = TestItemIds::NORMAL_ITEM_1;
    willAdd1.count = 1;
    willAdd1.quality = TestQuality::WHITE;
    willAdd1.bind = false;
    
    willAdd2.itemId = TestItemIds::NORMAL_ITEM_2;
    willAdd2.count = 1;
    willAdd2.quality = TestQuality::WHITE;
    willAdd2.bind = false;
    
    // 同时进行操作
    int result1 = opMgr1->AddToBag(willAdd1, 1, nullptr);
    int result2 = opMgr2->AddToBag(willAdd2, 1, nullptr);
    
    ASSERT_EQ(result1, 0) << "第一个操作管理器添加失败";
    ASSERT_EQ(result2, 0) << "第二个操作管理器添加失败";
    
    // 提交操作
    int commit1 = opMgr1->Commit();
    int commit2 = opMgr2->Commit();
    
    ASSERT_EQ(commit1, 0) << "第一个操作管理器提交失败";
    ASSERT_EQ(commit2, 0) << "第二个操作管理器提交失败";
    
    // 验证两个物品都已添加
    int count1 = 0, count2 = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_1, count1);
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_2, count2);
    
    ASSERT_EQ(count1, 1) << "第一个物品数量不正确";
    ASSERT_EQ(count2, 1) << "第二个物品数量不正确";
}

// === 内存和资源限制测试 ===

/**
 * @brief 测试大量物品操作
 */
TEST_F(EdgeCaseTest, MassiveItemOperationsTest) {
    // 测试添加大量不同种类的物品
    const int itemCount = 100;
    
    NFBagPageOpMgr* opMgr = CreateTestBagOpMgr(m_testPlayer, TEST_REASON_SYSTEM, true);
    
    // 添加大量物品
    for (int i = 0; i < itemCount; ++i) {
        WillAddItemData willAdd;
        willAdd.itemId = TestItemIds::NORMAL_ITEM_1 + i;
        willAdd.count = 1;
        willAdd.quality = TestQuality::WHITE;
        willAdd.bind = false;
        
        int result = opMgr->AddToBag(willAdd, 1, nullptr);
        // 由于背包容量限制，后面的添加可能会失败，这是正常的
        if (result != 0) {
            break; // 背包已满，停止添加
        }
    }
    
    // 提交操作
    int commitResult = opMgr->Commit();
    ASSERT_EQ(commitResult, 0) << "提交大量物品操作失败";
    
    // 验证添加了一些物品
    int totalItems = 0;
    for (int i = 0; i < itemCount; ++i) {
        int count = 0;
        NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_1 + i, count);
        totalItems += count;
    }
    
    ASSERT_GT(totalItems, 0) << "应该至少添加了一些物品";
}

/**
 * @brief 测试频繁的添加删除操作
 */
TEST_F(EdgeCaseTest, FrequentAddRemoveTest) {
    const int operationCount = 50;
    
    // 频繁添加和删除同一物品
    for (int i = 0; i < operationCount; ++i) {
        // 添加物品
        int addResult = NFServicePackage::AddByItemIDAndNum(
            m_testPlayer, TEST_REASON_SYSTEM, TestItemIds::STACKABLE_ARROW, 10);
        ASSERT_EQ(addResult, 0) << "第" << i << "次添加物品失败";
        
        // 删除物品
        int delResult = NFServicePackage::DelItemByItemIDAndNum(
            m_testPlayer, TEST_REASON_SYSTEM, TestItemIds::STACKABLE_ARROW, 5, nullptr);
        ASSERT_EQ(delResult, 0) << "第" << i << "次删除物品失败";
    }
    
    // 验证最终状态
    int finalCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::STACKABLE_ARROW, finalCount);
    ASSERT_EQ(finalCount, operationCount * 5) << "频繁操作后最终数量不正确";
}

// === 异常状态恢复测试 ===

/**
 * @brief 测试操作失败后的状态恢复
 */
TEST_F(EdgeCaseTest, FailureRecoveryTest) {
    // 获取初始状态
    int initialCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_1, initialCount);
    
    // 尝试无效操作
    int invalidResult = NFServicePackage::AddByItemIDAndNum(
        m_testPlayer, TEST_REASON_SYSTEM, -1, 1);
    ASSERT_NE(invalidResult, 0) << "无效操作应该失败";
    
    // 验证状态没有改变
    int afterInvalidCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_1, afterInvalidCount);
    ASSERT_EQ(afterInvalidCount, initialCount) << "无效操作后状态应该不变";
    
    // 进行正常操作验证系统仍然工作
    int validResult = NFServicePackage::AddByItemIDAndNum(
        m_testPlayer, TEST_REASON_SYSTEM, TestItemIds::NORMAL_ITEM_1, 1);
    ASSERT_EQ(validResult, 0) << "失败后的正常操作应该成功";
    
    // 验证正常操作生效
    int finalCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_1, finalCount);
    ASSERT_EQ(finalCount, initialCount + 1) << "失败后的正常操作应该正确执行";
}

/**
 * @brief 测试事务回滚后的状态
 */
TEST_F(EdgeCaseTest, TransactionRollbackRecoveryTest) {
    // 获取初始状态
    int initialCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_1, initialCount);
    
    {
        // 在作用域内创建操作管理器（不提交）
        NFBagPageOpMgr opMgr(m_testPlayer, TEST_REASON_SYSTEM, false);
        
        WillAddItemData willAdd;
        willAdd.itemId = TestItemIds::NORMAL_ITEM_1;
        willAdd.count = 1;
        willAdd.quality = TestQuality::WHITE;
        willAdd.bind = false;
        
        int result = opMgr.AddToBag(willAdd, 5, nullptr);
        ASSERT_EQ(result, 0) << "临时添加物品失败";
        
        // 作用域结束，操作管理器析构，未提交的操作应该被回滚
    }
    
    // 验证回滚后状态
    int afterRollbackCount = 0;
    NFServicePackage::GetBagItemTotalNumByItemID(m_testPlayer, TestItemIds::NORMAL_ITEM_1, afterRollbackCount);
    ASSERT_EQ(afterRollbackCount, initialCount) << "回滚后状态应该恢复到初始状态";
    
    // 验证系统仍然正常工作
    int normalResult = NFServicePackage::AddByItemIDAndNum(
        m_testPlayer, TEST_REASON_SYSTEM, TestItemIds::NORMAL_ITEM_1, 1);
    ASSERT_EQ(normalResult, 0) << "回滚后的正常操作应该成功";
} 